home *** CD-ROM | disk | FTP | other *** search
- /*===========================================
- DolphMorph(ドルフモーフ)
-
- モーフィング&変形アニメ作成ソフト
-
- モーフィングアルゴリズム: EAST 1994
- インターフェース作成: 松内 良介 1994
- ===========================================*/
- /*
- EAST氏によるモーフィングアルゴリズム
-
- 速度測定: 1994.9.6-00 1.15 clocks/loop
- 1994.9.6-01 1.17 clocks/loop
- 1994.9.6-02 1.07 clocks/loop
- 1994.9.6-03 1.00 clocks/loop
- 1994.9.6-04 0.91 clocks/loop
- 1994.9.6-05 1.08 clocks/loop (座標バッファを動的確保)
- 誰かもっと速くしてくれ~(笑)
-
- void morphInitialize(int width, int height, float limit,
- LIST *plMORPHPOINT, LIST *plMORPHLINE)
- void morphTerminate()
-
- static void do_line3(int x1,int y1,int t1, int x2,int y2,int t2,
- void func(int x,int y,int t)!)
- static void morphSetInit(void)
-
- int morphExec(float time, int (*func)(MORPH_INFO *info),
- int callCnt, int do_type)
- void morphGetColor(int x, int y, int *r, int *g, int *b)
- void morphDumpOut(char *filename, int wid, int ht)
- */
-
- #define CALLOC TL_calloc
- #define FREE TL_free
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <winb.h>
- #include <te.h>
- #include <fntb.h>
- #include <gui.h>
- #include <file_dlg.h>
- #include <egb.h>
- #include <ryosuke.h>
- #include <usrlib.h>
- #include <time.h>
- #include <math.h>
-
- #include "domorph.h"
- #include "fifo.h"
-
- #include "morphgo.h"
-
- #define _lim(a, min, max) (_min(_max((min),(a)), (max)))
-
- /*--------------------------------------------------------*/
- /* モジュール内変数 */
- /*--------------------------------------------------------*/
-
- static LIST *plPOINT;
- static LIST *plLINE;
- // static MORPH_POINT *p;
- // static int morph_point_num = 0;
- // static MORPH_LINE *l;
- // static int morph_line_num = 0;
-
- static fxp *from_x;
- static fxp *from_y;
- static fxp *to_x;
- static fxp *to_y;
- /* ↑from_x,from_y,to_x,to_y : 対応座標バッファ
- 横方向の要素数が morph_width+2, 縦方向の要素数が morph_height+2
- の2次元配列のイメージ。
- ただ実際には、morphInitialize 内で、1次元配列としてメモリ領域を
- 動的確保している。
- 中間画像上の点(x,y) について、
- (from_x[1+y][1+x], from_y[1+y][1+x])=画像Aに対応する座標
- (to_x[1+y][1+x], to_y[1+y][1+x]) =画像Bに対応する座標
- を表す。 */
- static fxp *tmp;
- /* ↑対応座標の収束計算のための一時バッファ。*/
- static char *mask;
- /* ↑対応座標の移動不可を表すフラグ。
- mask[1+y][1+x] が 0 なら…中間画像内(x,y)の対応座標は移動可
- mask[1+y][1+x] が 1 なら…中間画像内(x,y)の対応座標は移動不可
- これは、収束計算のときに境界点を移動させないために用いる。 */
- static int BUFWID;
- /* ↑from_x,from_y,to_x,to_y,mask,tmp の横要素数
- これは morph_width+2 に設定される。*/
- static fxp morph_limit = 0x10000;
- /* ↑対応座標の収束計算時の限界移動量
- (この値よりも移動量が小さくなったら計算を終了する)
- morphInitialize で設定。 */
- static int morph_width,morph_height;
- /* ↑モーフィング画像の横・縦のピクセル数
- morphInitialize で設定 */
- static fxp morph_t1 = UNIT;
- static fxp morph_t2 = 0;
- /* ↑現在計算中の中間画像の、画像A/B間での分率。
- 0x00000~0x10000 の値をとる(16ビット固定小数点)
- morphExec で設定 */
- static int morphType;
- /* DO_MORPH , DO_TRANSFORM */
-
- #define INDEX(x,y) ((1+(x)) + BUFWID * (1+(y)))
- #define IA(name,n) *((int*)(name) + (n))
- #define CA(name,n) *((char*)(name) + (n))
-
- /* ユーザー定義された色読み込み関数の外部定義 */
- extern int morphGetFromPixel(fxp x,fxp y,int *r,int *g,int *b);
- extern int morphGetToPixel(fxp x,fxp y,int *r,int *g,int *b);
-
- /*--------------------------------------------------------*/
- /* モーフィング処理の初期化/終了 */
- /*--------------------------------------------------------*/
-
- void morphInitialize(int width, int height, float limit,
- LIST *plMORPHPOINT, LIST *plMORPHLINE)
- {
- morph_width = width;
- morph_height = height;
- morph_limit = FP2FX(limit);
- plPOINT = plMORPHPOINT;
- plLINE = plMORPHLINE;
- // morph_point_num = point_num;
- // p = point;
- // morph_line_num = line_num;
- // l = line;
- from_x = (fxp*)CALLOC(sizeof(fxp), (width+2)*(height+2));
- from_y = (fxp*)CALLOC(sizeof(fxp), (width+2)*(height+2));
- to_x = (fxp*)CALLOC(sizeof(fxp), (width+2)*(height+2));
- to_y = (fxp*)CALLOC(sizeof(fxp), (width+2)*(height+2));
- tmp = (fxp*)CALLOC(sizeof(fxp), (width+2)*(height+2));
- mask = (char*)CALLOC(sizeof(char), (width+2)*(height+2));
- BUFWID = width + 2;
- }
-
- void morphTerminate()
- {
- FREE(from_x);
- FREE(from_y);
- FREE(to_x);
- FREE(to_y);
- FREE(tmp);
- FREE(mask);
- }
-
- /*--------------------------------------------------------*/
- /* 線分アルゴリズム */
- /*--------------------------------------------------------*/
-
- static void do_line3(int x1,int y1,int t1, int x2,int y2,int t2,
- void func(int x,int y,int t)!)
- /* (x1,y1)~(x2,y2) の直線上の各点を求める。その際、始点 で t1、
- 終点で t2 となるような値 t も同時に求め、各点について関数
- func (x,y,t) を呼び出す。*/
- {
- int xr,yr,tr,dx,dy,dt,x,y,t;
- xr=abs(x2-x1),yr=abs(y2-y1),tr=abs(t2-t1);
- func(x1,y1,t1); // 最初の点
- if (xr==0 && yr==0)
- ;
- else if (xr >= yr)
- {
- dy = (yr<<16) / xr; if(y1>y2) dy = -dy;
- dt = (tr<<16) / xr; if(t1>t2) dt = -dt;
- if (x1 < x2)
- for (x=x1+1, y=(y1<<16)+0x8000+dy, t=(t1<<16)+0x8000+dt;
- x <= x2; x++, y+=dy, t+=dt)
- func(x,y>>16,t>>16);
- else
- for (x=x1-1, y=(y1<<16)+0x8000+dy, t=(t1<<16)+0x8000+dt;
- x >= x2; x--, y+=dy, t+=dt)
- func(x,y>>16,t>>16);
- }
- else
- {
- dx = (xr<<16) / yr; if(x1>x2) dx = -dx;
- dt = (tr<<16) / yr; if(t1>t2) dt = -dt;
- if (y1 < y2)
- for (y=y1+1, x=(x1<<16)+0x8000+dx, t=(t1<<16)+0x8000+dt;
- y <= y2; y++, x+=dx, t+=dt)
- func(x>>16,y,t>>16);
- else
- for (y=y1-1, x=(x1<<16)+0x8000+dx, t=(t1<<16)+0x8000+dt;
- y >= y2; y--, x+=dx, t+=dt)
- func(x>>16,y,t>>16);
- }
- }
-
- /*--------------------------------------------------------*/
- /* 境界条件の設定 */
- /*--------------------------------------------------------*/
-
- static void morphSetInit(void)
- {
- // printf("morphSetInit begin\n");
- int x,y,idx;
- /* 対応座標配列を初期化 */
- for (y=-1; y<=morph_height; y++)
- for (x=-1,idx=INDEX(x,y); x<=morph_width; x++,idx++)
- {
- mask [idx] = (0 <= x && x < morph_width &&
- 0 <= y && y < morph_height ? 0 : 1);
- from_x[idx] = I2FX(x);
- from_y[idx] = I2FX(y);
- to_x [idx] = I2FX(x);
- to_y [idx] = I2FX(y);
- }
- /* 点タイプの境界条件設定 */
- if (plPOINT == NULL)
- goto NOPOINT;
- for (list_top(plPOINT); !list_isOut(plPOINT); list_next(plPOINT))
- {
- MORPH_POINT mp;
- list_getData(plPOINT,&mp);
- /* 中間画像上での境界点の座標を計算 */
- x = FX2I(mp.from.x * morph_t1 + mp.to.x * morph_t2);
- y = FX2I(mp.from.y * morph_t1 + mp.to.y * morph_t2);
- x = _lim(x,0,morph_width-1);
- y = _lim(y,0,morph_height-1);
- /* 境界点について、画像A/Bへの対応座標を設定 */
- // printf(" morphSetInit (point %d,%d from=%d,%d to=%d,%d)\n",
- // x,y, mp.from.x, mp.from.y, mp.to.x, mp.to.y);
- idx = INDEX(x,y);
- from_x[idx] = I2FX(mp.from.x);
- from_y[idx] = I2FX(mp.from.y);
- to_x [idx] = I2FX(mp.to.x);
- to_y [idx] = I2FX(mp.to.y);
- mask [idx] = 1; /* 境界点では対応座標は移動させない */
- }
- NOPOINT:;
- /* 線指定境界条件の設定 */
- if (plLINE == NULL)
- goto NOLINE;
- for (list_top(plLINE); !list_isOut(plLINE); list_next(plLINE))
- {
- // printf(" morphSetInit (line)\n");
- MORPH_LINE ml;
- list_getData(plLINE, &ml);
- int tx1,ty1,tx2,ty2;
- #define L ml
- /* 中間画像上での境界線分の始点・終点座標を計算 */
- tx1 = FX2I(L.from1.x * morph_t1 + L.to1.x * morph_t2);
- ty1 = FX2I(L.from1.y * morph_t1 + L.to1.y * morph_t2);
- tx2 = FX2I(L.from2.x * morph_t1 + L.to2.x * morph_t2);
- ty2 = FX2I(L.from2.y * morph_t1 + L.to2.y * morph_t2);
- /* 境界線分上の点ついて、画像A/Bへの対応座標を設定する関数 */
- void pset(int x,int y,int s)
- /* (x,y):境界線分上の点の座標
- s:0x0000(始点)~0x1000(終点) 線分のなかのどの位置か
- (12ビット固定少数点) */
- {
- int r;
- r = 0x1000 - s;
- idx = INDEX(x,y);
- /* r,s は12bit固定小数点だが、求めるべき対応座標は16bit
- 固定小数点なので、4ビット上位へシフトしてから代入 */
- from_x[idx] = (L.from1.x * r + L.from2.x * s) << 4;
- from_y[idx] = (L.from1.y * r + L.from2.y * s) << 4;
- to_x [idx] = (L.to1.x * r + L.to2.x * s) << 4;
- to_y [idx] = (L.to1.y * r + L.to2.y * s) << 4;
- mask [idx] = 1;
- }
- /* 境界線分上の各点について、対応座標を設定 */
- do_line3(tx1,ty1,0x0000, tx2,ty2,0x1000, pset);
- #undef L
- }
- NOLINE:;
- END:;
- // printf("morphSetInit end\n");
- return;
- }
-
- /*--------------------------------------------------------*/
- /* 初期対応座標の設定 */
- /*--------------------------------------------------------*/
-
- static void morphSetFromTo(void)
- {
- /* x 方向 */
- int x,y;
- for (y=0; y<morph_height; y++)
- {
- int idx0;
- int left;
- idx0 = INDEX(0,y);
- left = -1;
- for (x=-1; x<=morph_width; )
- {
- if (mask[idx0+x] == 0)
- x++;
- else
- {
- // それまでの非マスク領域について、マスク座標を内分
- if (x > left)
- {
- int fx1,fx2,tx1,tx2;
- fx1 = (from_x[idx0+left] + 128) >> 8; // 8bit fixed.p.
- fx2 = (from_x[idx0+ x] + 128) >> 8;
- tx1 = (to_x [idx0+left] + 128) >> 8;
- tx2 = (to_x [idx0+ x] + 128) >> 8;
- int k,ip,ipwid,h;
- ipwid = x-left;
- h = ipwid / 2;
- for (k=left+1,ip=1; k<=x-1; k++,ip++)
- {
- from_x[idx0+k]=((fx1*(ipwid-ip)+fx2*ip+h)/ipwid)<<8;
- to_x [idx0+k]=((tx1*(ipwid-ip)+tx2*ip+h)/ipwid)<<8;
- }
- }
- while (mask[idx0+x] == 1 && x <= morph_width)
- x++;
- left = x-1;
- }
- }
- }
- /* y 方向 */
- for (x=0; x<morph_width; x++)
- {
- int idx0;
- int top;
- idx0 = INDEX(x,0);
- top = 0;
- for (y=-1; y<=morph_height; )
- {
- if (mask[idx0+BUFWID*y] == 0)
- y++;
- else
- {
- // それまでの非マスク領域について、マスク座標を内分
- if (y > top)
- {
- int fy1,fy2,ty1,ty2;
- fy1 = (from_y[idx0+BUFWID * top] + 128) >> 8;
- fy2 = (from_y[idx0+BUFWID * y] + 128) >> 8;
- ty1 = (to_y [idx0+BUFWID * top] + 128) >> 8;
- ty2 = (to_y [idx0+BUFWID * y] + 128) >> 8;
- int k,ip,ipwid,h;
- ipwid = y-top;
- h = ipwid / 2;
- for (k=top+1,ip=1; k<=y-1; k++,ip++)
- {
- from_y[idx0+BUFWID*k] =
- ((fy1*(ipwid-ip)+fy2*ip+h)/ipwid) << 8;
- to_y [idx0+BUFWID*k] =
- ((ty1*(ipwid-ip)+ty2*ip+h)/ipwid) << 8;
- }
- }
- while (mask[idx0+BUFWID*y] == 1 && y <= morph_height)
- y++;
- top = y - 1;
- }
- } // for y
- } // for x
- }
-
- /*--------------------------------------------------------*/
- /* 対応座標の収束計算 */
- /*--------------------------------------------------------*/
-
- int morphExec(float time, int (*func)(MORPH_INFO *info), int callCnt,
- int do_type)
- /* morphInitialize 呼び出しの後にこの関数を呼び出すことで、
- 対応座標(from_x,from_y,to_x,to_y)の収束計算が行われる。 */
- /* 引数 time には、画像A/B間の分率を 0.0 ~ 1.0 の値で設定する。
- つまり、0.0 を設定すると画像Aそのものが、1.0 を設定すると画像B
- そのものが得られる */
- /* do_type : DO_MORPH / DO_TRANSFORM */
- /* この関数を実行後、morphGetColor により、中間画像の各ピクセルを
- 得ることができる。*/
- /* 収束計算の途中で、callCnt 回のループごとに関数 func を呼び出す
- 関数 func が0以外の値を返せば、計算を中断 */
- /* 返値 0=通常終了 -1=中断された */
-
- {
- int vv;
- morphType = (do_type == DO_TRANSFORM ? DO_TRANSFORM : DO_MORPH);
- /* 中間画像の画像A/B間での分率を morph_t1, morph_t2 に設定
- (12ビット固定小数点) */
- morph_t2 = FP2FX(time);
- morph_t2 = _lim(morph_t2, 0, UNIT);
- morph_t1 = UNIT - morph_t2;
- /* 境界条件の指定 */
- morphSetInit();
- /* 初期対応座標の設定 */
- morphSetFromTo();
- /* 収束計算 (vv ごとに、from_x, from_y, to_x, to_y の順) */
- for (vv=0; vv<(morphType == DO_TRANSFORM ? 2 : 4); vv++)
- {
- int i;
- int flag;
- int *var;
- /* 無視して良い計算は無視。 */
- if (morphType == DO_MORPH)
- {
- if (morph_t1 == 0 && (vv==0||vv==1))
- continue;
- if (morph_t2 == 0 && (vv==2||vv==3))
- continue;
- }
- var = (vv==0 ? from_x : vv==1 ? from_y :
- vv==2 ? to_x : to_y);
- unsigned int clk1,clk2;
- clk1 = clock(); // 実行時間計測開始
- int callCheck;
- callCheck = 0;
- for (i=0;i<=10000;i++)
- {
- int x,y,idx;
- /* 中間画像内の全ての点について、その点の対応座標を再計算
- (その点の上下左右の点に設定されている対応座標の平均を、
- 新たな対応座標として計算→いったん tmp に一時登録する) */
- for (y=0; y<morph_height; y++)
- {
- /* まずは横16ピクセルずつまとめて処理 */
- for (x=0,idx=INDEX(x,y); x+16<=morph_width; x+=16)
- {
- int *p;
- p = var + idx;
- #define DO \
- tmp[idx] = (p[-1]+p[1]+p[-BUFWID]+p[BUFWID])>>2; \
- p++,idx++;
- DO DO DO DO DO DO DO DO
- DO DO DO DO DO DO DO DO
- #undef DO
- }
- /* 残りの 0 ~ 15 ピクセルを処理 */
- for (; x<morph_width; x++,idx++)
- tmp[idx] = ( var[idx-1] + var[idx+1] +
- var[idx-BUFWID] + var[idx+BUFWID] ) >> 2;
- }
- /* 対応座標の移動可・不可フラグに従い、実際に対応座標を更新 */
- /* 同時に、対応座標の最大移動量 (flag) も求める */
- flag = 0;
- for (y=0; y<morph_height; y++)
- {
- #if 1
- /* まずは横8ピクセルずつまとめて処理 */
- for(x=0,idx=INDEX(x,y); x+8<=morph_width; x+=8)
- {
- #define DO \
- if(mask[idx] == 0) \
- { \
- int f; \
- f = abs(tmp[idx] - var[idx]); \
- if (f > flag) flag = f; \
- var[idx] = tmp[idx]; \
- } \
- idx++;
- DO DO DO DO DO DO DO DO
- #undef DO
- }
- /* 残りの0~7ピクセルを処理 */
- for (; x<morph_width; x++,idx++)
- {
- if(mask[idx] == 0)
- {
- int f = abs(tmp[idx] - var[idx]);
- if (f > flag) flag = f;
- var[idx] = tmp[idx];
- }
- }
- #else
- /* まずは横8ピクセルずつまとめて処理 */
- for(x=0,idx=INDEX(x,y); x+8<=morph_width; )
- {
- #define DO \
- if(mask[idx] == 0) \
- { \
- int f; \
- f = abs(tmp[idx] - var[idx]); \
- if (f > flag) flag = f; \
- var[idx] = tmp[idx]; \
- } \
- else if (i==0||i==1||i==2) \
- ; /* printf("morphExec: point(%d,%d,%3.1f,%3.1f)\n",x,y,FX2FP(var[idx-1]),FX2FP(var[idx+1])); */ \
- idx++,x++;
- DO DO DO DO DO DO DO DO
- #undef DO
- }
- /* 残りの0~7ピクセルを処理 */
- for (; x<morph_width; x++,idx++)
- {
- if(mask[idx] == 0)
- {
- int f = abs(tmp[idx] - var[idx]);
- if (f > flag) flag = f;
- var[idx] = tmp[idx];
- }
- else if (i==0||i==1||i==2)
- ; /* printf("morphExec: point(%d,%d)\n",x,y); */
- }
- #endif
- }
- /* 対応座標の移動量が小さいなら、収束したということなので終了 */
- if (flag < morph_limit) break;
- if (func != 0)
- {
- if (callCheck <= 0)
- {
- MORPH_INFO info;
- info.varType = vv;
- info.loopCnt = i;
- info.moveMax = flag;
- info.moveLimit = morph_limit;
- info.morphType = morphType;
- if ((*func)(&info) != 0)
- goto BREAK;
- callCheck = callCnt;
- }
- else
- callCheck--;
- }
- }
- // printf("morphExec:\n");
- clk2 = clock(); // 実行時間計測終了
- // if (i >= 200)
- // printf("loop rate: %lf clocks/loop\n",
- // (float)(clk2-clk1)/(float)i);
- // printf("%d i=%ld, %lf\n",vv,i,FX2FP(flag));
- // char msg[200];
- // sprintf(msg,"%d i=%ld, %lf\n",vv,i,FX2FP(flag));
- // morphgo_msg(msg);
- }
- END:;
- return 0;
- BREAK:;
- return -1;
- }
-
- /*--------------------------------------------------------*/
- /* 中間画像の各ピクセルの取得 */
- /*--------------------------------------------------------*/
-
- // ★このへんのモジュール分割はむちゃくちゃ。要再考。
-
- void morphGetColor(int x,int y, int *r,int *g,int *b)
- {
- int idx;
- int r1,g1,b1,r2,g2,b2;
- idx = INDEX(x,y);
- if (morphType == DO_MORPH)
- {
- if (morphgo_getBackFlag())
- {
- int c;
- c = morphgo_getBackImagePixel(x,y);
- if (morphGetFromPixel(from_x[idx],from_y[idx],&r1,&g1,&b1)!=0)
- {
- g1 = (c >> 10) & 0x1f;
- r1 = (c >> 5) & 0x1f;
- b1 = (c ) & 0x1f;
- }
- if (morphGetToPixel(to_x[idx], to_y[idx], &r2,&g2,&b2) != 0)
- {
- g2 = (c >> 10) & 0x1f;
- r2 = (c >> 5) & 0x1f;
- b2 = (c ) & 0x1f;
- }
- }
- else
- {
- morphGetFromPixel(from_x[idx],from_y[idx],&r1,&g1,&b1);
- morphGetToPixel(to_x[idx], to_y[idx], &r2,&g2,&b2);
- }
- *r = FX2I(r1 * morph_t1 + r2 * morph_t2);
- *g = FX2I(g1 * morph_t1 + g2 * morph_t2);
- *b = FX2I(b1 * morph_t1 + b2 * morph_t2);
- }
- else if (morphType == DO_TRANSFORM)
- {
- if (morphgo_getBackFlag())
- {
- int c;
- c = morphgo_getBackImagePixel(x,y);
- if (morphGetFromPixel(from_x[idx], from_y[idx], r,g,b) != 0)
- {
- *g = (c >> 10) & 0x1f;
- *r = (c >> 5) & 0x1f;
- *b = (c ) & 0x1f;
- }
- }
- else
- morphGetFromPixel(from_x[idx], from_y[idx], r,g,b);
- }
- return;
- }
-
- /*--------------------------------------------------------*/
- /* ダンプ出力(デバッグ用) */
- /*--------------------------------------------------------*/
-
- void morphDumpOut(char *filename,int wid,int ht)
- {
- int *var;
- int x,y,idx;
- var = from_x;
- FILE *fp;
- if ((fp = fopen(filename, "w")) == NULL)
- return;
- for (y=0; y<ht; y++)
- {
- for (x=0,idx=INDEX(x,y); x<wid; x++,idx++)
- {
- if (mask[idx] == 0)
- fprintf(fp,"%5.1f ",FX2FP(var[idx]));
- else
- fprintf(fp,"%3d * ",FX2I(var[idx]));
- }
- fprintf(fp,"\n");
- }
- fclose(fp);
- }
-
- /* [end] */
-